from django.db import transaction
from django.db.models import QuerySet
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError

from apps.samples.constants import OPEN, RELEASE, CLOSE
from apps.samples.filters import SamplesFilter
from apps.samples.models import Samples
from apps.samples.serializers import SamplesSerializer, SamplesRawQuerySerializer
from bases.response import SuccessResponse
from bases.viewsets import APIModelViewSet, APIRawQueryViewSet
from utils.utils import update_instance


class SamplesViewSet(APIModelViewSet):
    # 不排序的话默认是按照id进行倒叙
    queryset = Samples.objects.all()
    serializer_class = SamplesSerializer

    # 该方式不支持模糊查询，lookup_expr=exact
    # 低版本django-filter不再支持filter_fields，而是使用filterset_fields，本系统为了适配低版本重新加上了filter_fields
    # filter_fields = ('item_no', 'status')

    # 需要支持模糊查询时使用以下方式
    # 低版本django-filter不再支持filter_class，而是使用filterset_class，本系统为了适配低版本重新加上了filter_class
    filter_class = SamplesFilter

    @transaction.atomic
    def perform_destroy(self, instance):
        if isinstance(instance, QuerySet):
            # 批量删除时，instance将是queryset对象
            # 如果允许批量删除，则遍历queryset进行数据校验并删除
            raise ValidationError('当前接口不允许进行批量删除操作')
        else:
            # 单个删除时，instance即模型实例
            if instance.status != OPEN:
                raise ValidationError('只有开放状态下的数据可以进行删除操作')
        super().perform_destroy(instance)

    @transaction.atomic
    @action(detail=True, methods=['put'])
    def release(self, request, *args, **kwargs):
        instance = self.get_object()
        if instance.status != OPEN:
            raise ValidationError('只有开放状态下的数据可以进行生效操作')
        instance.status = RELEASE
        update_instance(instance, request)
        instance.save()
        return SuccessResponse()

    @transaction.atomic
    @action(detail=True, methods=['put'])
    def close(self, request, *args, **kwargs):
        instance = self.get_object()
        if instance.status != RELEASE:
            raise ValidationError('只有开生效态下的数据可以进行关闭操作')
        instance.status = CLOSE
        update_instance(instance, request)
        instance.save()
        return SuccessResponse()


class SamplesRawQueryViewSet(APIRawQueryViewSet):
    """
    使用原生SQL开发ViewSet
    lookup 的取值范围 ['exact', 'contains', 'in', 'gt', 'gte', 'lt', 'lte']
    type 取值范围 ['char', 'number', 'date', 'datetime']
    type支持的lookup {
        'char': {
            'exact': '=',
            'in': 'in',
            'contains': 'like'
        },
        'number': {
            'exact': '=',
            'in': 'in',
            'gt': '>',
            'lt': '<',
            'gte': '>=',
            'lte': '<='
        },
        'date': {
            'exact': '=',
            'gt': '>',
            'lt': '<',
            'gte': '>=',
            'lte': '<='
        },
        'datetime': {
            'exact': '=',
            'gt': '>',
            'lt': '<',
            'gte': '>=',
            'lte': '<='
        }
    }
    """
    raw_query = 'select item_no, warehouse, location, valid_date, invalid_date, quantity from samples'
    serializer_class = SamplesRawQuerySerializer
    filter_rule = {
        'item_no': {
            'field': 'item_no',
            'type': 'char',
            'lookup': 'contains'
        },
        'valid_date_from': {
            'field': 'valid_date',
            'type': 'date',
            'lookup': 'gte'
        },
        'valid_date_to': {
            'field': 'valid_date',
            'type': 'date',
            'lookup': 'lt'
        },
        'quantity': {
            'field': 'quantity',
            'type': 'number',
            'lookup': 'gt'
        }
    }

    def handler(self, resp_data):
        """
        重写handler方法，修改响应数据
        示例中是在响应数据中增加两个Row Query之外的字段以及值
        @param resp_data:
        @return:
        """
        for data in resp_data:
            data.update({'current_year': 2023, 'current_month': 9})
        return resp_data
